package ru.michaeltyan.familyconnector.businessobjects.impl;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ru.michaeltyan.familyconnector.beans.Foodstuff;
import ru.michaeltyan.familyconnector.beans.FoodstuffList;
import ru.michaeltyan.familyconnector.businessobjects.FoodstuffManagerBusinessObject;
import ru.michaeltyan.familyconnector.cache.Cache;
import ru.michaeltyan.familyconnector.dao.FoodstuffManagerDao;

public class FoodstuffManagerBusinessObjectImpl implements FoodstuffManagerBusinessObject {

	private FoodstuffManagerDao foodstuffManagerDao;

	private Cache cache;

	protected final Log logger = LogFactory.getLog(getClass());

	public void setFoodstuffManagerDao(FoodstuffManagerDao foodstuffManagerDao) {
		this.foodstuffManagerDao = foodstuffManagerDao;
	}

	public List<Foodstuff> findAll() {
		return foodstuffManagerDao.getAllFoodstuffs();
	}

	public List<FoodstuffList> findLists() {
		return foodstuffManagerDao.getAllFoodstuffLists();
	}

	public List<Foodstuff> findByList(FoodstuffList foodstuffList) {
		List<Foodstuff> foodstuffs = new ArrayList<Foodstuff>();
		for (Foodstuff foodstuff : foodstuffList.getListFoodstuff()) {
			foodstuffs.add(foodstuff);
		}
		return foodstuffs;
	}

	public List<Foodstuff> findByListWithCache(FoodstuffList foodstuffList) throws IOException, ClassNotFoundException, SQLException {
		Connection conn = foodstuffManagerDao.openConnection();
		List<Foodstuff> foodstuffs = null;
		try {
			List<Long> allIds = foodstuffManagerDao.getAllIdsOfFoodstuffLists(conn, foodstuffList.getId());
			List<Long> idsNotInCache = getIdsNotInCache(allIds);
			List<Long> idsInCache = removeIdsNotInCache(allIds, idsNotInCache);
			logger.info(idsInCache.size() + " ids in cache; " + idsNotInCache.size() + " ids not in cache.");
			foodstuffs = getFoodstuffs(idsInCache, idsNotInCache, conn);
		} finally {
			foodstuffManagerDao.closeConnection(conn);
		}
		return foodstuffs;
	}

	private List<Foodstuff> getFoodstuffs(List<Long> idsInCache, List<Long> idsNotInCache, Connection conn) throws IOException, ClassNotFoundException, SQLException {
		List<Foodstuff> foodstuffs = extractFoodstuffsFromCache(idsInCache);
		List<Foodstuff> foodstuffsToCache = addFoodstuffsToCache(idsNotInCache, conn);
		foodstuffs.addAll(foodstuffsToCache);
		return foodstuffs;
	}

	private List<Foodstuff> extractFoodstuffsFromCache(List<Long> idsInCache) throws IOException, ClassNotFoundException {
		List<Foodstuff> foodstuffs = new ArrayList<Foodstuff>();
		for (Long id : idsInCache) {
			foodstuffs.add(cache.extractFoodstuff(id));
		}
		return foodstuffs;
	}

	private List<Foodstuff> addFoodstuffsToCache(List<Long> idsNotInCache, Connection conn) throws IOException, SQLException {
		List<Foodstuff> foodstuffsToCache = new ArrayList<Foodstuff>();
		for (Long id : idsNotInCache) {
			Foodstuff foodstuff = foodstuffManagerDao.getFoodstuffById(id, conn);
			foodstuffsToCache.add(foodstuff);
		}
		cache.putFoodstuffs(foodstuffsToCache);
		return foodstuffsToCache;
	}

	public void setCache(Cache cache) {
		this.cache = cache;
	}

	public Cache getCache() {
		return this.cache;
	}

	private List<Long> getIdsNotInCache(List<Long> idsInCache) {
		List<Long> idsNotInCache = new ArrayList<Long>();
		for (int i = 0; i < idsInCache.size(); i++) {
			Long id = idsInCache.get(i);
			if (!(cache.containsFoodstuff(id))) {
				logger.info(idsInCache.get(i) + " not in cache.");
				idsNotInCache.add(idsInCache.get(i));
			}
		}
		return idsNotInCache;
	}

	private List<Long> removeIdsNotInCache(List<Long> allIds, List<Long> idsNotInCache) {
		allIds.removeAll(idsNotInCache);
		return allIds;
	}
}
